/**
 * @class   wosh::PropertiesProvider
 * @brief   Class/interface for Objects which provide wosh::Property, some
 *          helper functions are provided for convenience.
 *
 *Sorted Associative Container t
 Unique Associative Container,
 * - Pure STL
 * - requirement tree:
 *   - std::string, std::map, std::vector
 *   - wosh::Property
 *     - wosh::Data
 *   - wosh::Permission
 *
 * Container is std::map
 *
 *
 * \code

Properties.setProperty( "MyKeyName_str", "plain text string", Permission( Permission::Read ) );
Properties.setProperty( "MyKeyName_int", 456, Permission( Permission::RW,  Permission::Read, Permission::Read ) );
Properties.setProperty( "MyKeyName_timestamp", Data(Utilities::std_time(), Data::DATETIME), Permission( Permission::Read ) );

 * \endcode
 *
 * \code
Properties.setPropertiesProviderListener(this);
 * \endcode
 *
 *
 * \code

bool BundleGeneric::readingProperty( Property* property_curr, const PropertiesProvider* source )
 {
	(void)property_curr; (void)source;
	// usually we don't need to implement this, but some Bundles (or especially devices)
	// may optimize the reflesh of information inline (here)
	// NOTE that caller will execute this code, usually from another Thread, processing should be
	// very STABLE and FAST.

	return true;
 }

 * \endcode
 *
 *
 * \code

bool BundleGeneric::updatingProperty( Property* property_new, const Property* property_old, const PropertiesProvider* source )
 {
	(void)source; (void)property_old;
	if ( property_new == NULL ) // property was removed
		return true;
	// permission check is done by get/set/list methods, so the operation is generally allowed
	// basically we just need to apply the new settings for real, often the Property is a "shadow" variable
	// or there are more conseguances when changing it.
	// Moreover some property/values shall be validated or translated.
	// NOTE that caller will execute this code, usually from another Thread, processing should be
	// very STABLE and FAST. Be aware of DeadLock: you can't access/edit properties from here.

	if ( property_new->getKey() == _KEY_name ) { // if we are here, we allow to edit name
		Log(LOG_VERBOSE, " Changing Bundle Name, Log-Context will change to '%s'", property_new->getValue().getData().c_str() );
		Object::setName(property_new->getValue().getData());
		Log.setContext(property_new->getValue().getData());
		return true;
	 }

 * \endcode
 *

 *
 *
 *
 ****************************************************************************
 * @version $Id: PropertiesProvider.h 2863 2010-08-07 04:28:58Z alex $
 * @author  Alessandro Polo
 ****************************************************************************/
/* Copyright (c) 2007-2010, WOSH - Wide Open Smart Home 
 * by Alessandro Polo - OpenSmartHome.com
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *     * Neither the name of the OpenSmartHome.com WOSH nor the
 *       names of its contributors may be used to endorse or promote products
 *       derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY Alessandro Polo ''AS IS'' AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL Alessandro Polo BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 ****************************************************************************/

#ifndef __WOSH_Core_PropertiesProvider_H__
 #define __WOSH_Core_PropertiesProvider_H__

 #include <woshDefs.h>
 #include <core/Containers.h>
 #include <core/Property.h>
 #include <core/Permission.h>
 #include <core/Serialization.h>
 #include <vector>


namespace wosh {

class PropertyHolder
 {
	public:
		PropertyHolder() {
			reset();
		 }
		~PropertyHolder() {
			if ( data != NULL )
				delete data;
		 }

	public:
		mutable Property* data;		///< real contents
		mutable MutexRW mux;

		bool monitorRead;			///< monitor read operation
		bool monitorWrite;			///< monitor write operation
		bool monitorExecute;		///< monitor instert/delete operation
		// callback

		inline const Property* getProperty() const	{ return this->data; }
		inline Property* getProperty()				{ return this->data; }

		inline void transactionBeginRead() const	{ mux.lockForRead(); }
		inline void transactionBeginWrite() const	{ mux.lockForWrite(); }
		inline void transactionEnd() const			{ mux.unLock(); }

		inline void reset() {
			data = NULL;
			monitorRead = monitorWrite = monitorExecute = false;
		 }

	public:
		static DataFieldCollector<PropertyHolder>* getDataFields();

 };

class Object;
class List;
class Table;
class IPropertiesProviderListener;

class PropertiesProvider :	public MapT<std::string, PropertyHolder*>,
							public ISerializable
 {
	WOSH_SERIALIZABLE(wosh::PropertiesProvider)
	WOSH_COMPARE_RTTI(wosh::PropertiesProvider)

	public:
		/**
		 * @brief  Default constructor.
		 * @param owner [in] the parent object, used to initialize listPermission
		 */
		PropertiesProvider( const Object* owner = NULL );
		/**
		 * @brief  Copy constructor.
		 * @param m [in] the source object to be copied
		 */
		PropertiesProvider( const PropertiesProvider& m );
		/**
		 * @brief  Empty destructor.
		 */
		virtual ~PropertiesProvider();


	public:
		virtual PropertiesProvider& intersect( PropertiesProvider& props, bool overwrite_value, bool overwrite_perms, bool callbacks = true );

		virtual WRESULT updateObjectKeys( const Object* object, short permission_overwrite_mode = Permission::Overwrite_OwnerGroup );


/** @name Property Getters (reentrant)
 * @{
 ******************************************************************************/
 	public:
		// (reentrant, callbacks) deep copy, very wasting
		Property get( const std::string& key ) const;

		// (non-locking, callbacks)
		Property* getCopyOf( const std::string& key ) const;

		// (reentrant, callbacks)
		Variant getValueOf( const std::string& key, const Variant& defaultValue = Variant::EmptyVariant ) const;

		// (reentrant, callbacks)
		Permission getPermissionOf( const std::string& key ) const;

		// (reentrant, callbacks)
		List* toList( short index ) const;
		// (reentrant, callbacks)
		Table* toTable( bool include_permission ) const;

//@}
/** @name Property Setters (reentrant)
 * @{
 ******************************************************************************/
 	public:
		// add/update (reentrant, callbacks)
		WRESULT set( const Property& prop );

		// add/acquire (non-locking, no callbacks)  || must be locked for write 
		WRESULT set( Property* prop );

		// add/update (reentrant, callbacks)
		WRESULT set( const std::string& key, const Variant& value );

		// add/update (non-locking, optional callbacks)
		WRESULT update( const std::string& key, const Variant& value, bool callback = false );

		// add/update (non-locking, callbacks)
		WRESULT set( const std::string& key, const Variant& value, const Permission& permission,
						short permission_overwrite_mode = Permission::Overwrite_All  );

		// add/update (reentrant:lock-write, callbacks)
		WRESULT remove( const std::string& key );

		// add/update (reentrant)
		WRESULT monitor( const std::string& key, bool write = true, bool read = false, bool removal = false );

		// non-list-locking, non-prop-locking, optional callback
		WRESULT updating( PropertyHolder* prop, const Variant& value, const Permission* permission, short permission_overwrite_mode, bool callback );
//e, const Permission* permission = NULL, short permission_overwrite_mode = Permission::Overwrite_None, bool callback = true );
		// non-list-locking, non-prop-locking, raise callback
		bool reading( const PropertyHolder* prop ) const;

//@}
/** @name Property Setters (non-locking, no callbacks)
 * @{
 ******************************************************************************/
 	public:
		inline void setDefaultPermission( const Permission& p )	{ this->defaultPermission = p; }

//@}

		inline const Permission& getDefaultPermission() const	{ return this->defaultPermission; }

		virtual void setPermission( const Permission& value, short overwrite_mode, bool when_empty, bool nested );

/** @name Getters
 * @{
 ******************************************************************************/
 	public:
		inline const Permission& getListPermission() const		{ return this->listPermission; }

//@}
/** @name Setters
 * @{
 ******************************************************************************/
 	public:
		inline void setListPermission( const Permission& p )	{ this->listPermission = p; }
		inline Permission& getListPermission()					{ return this->listPermission; }

		virtual void setPropertiesProviderListener( IPropertiesProviderListener* pp_listener );

//@}
/** @name Operators Overloading
 * @{
 ******************************************************************************/
	public:
		virtual PropertiesProvider& operator=(const PropertiesProvider& m);
		virtual bool operator==(const PropertiesProvider &other) const;
		virtual bool operator!=(const PropertiesProvider &other) const
																{ return !(*this == other);  }

		Variant operator[] (const std::string& key ) const		{ return getValueOf(key); }

//@}
/** @name Serialization interface
 * @{
 ******************************************************************************/
	public:
		virtual std::string toString() const;
		virtual bool updateHash( DataHashContext* hash_context ) const;
//@}
	protected:
		WRESULT _set_( const std::string& key, const Variant& value, const Permission* permission, short permission_overwrite_mode, bool callback );

	protected:
		Permission defaultPermission;				///< default permission for new properties
		Permission listPermission;					///< permission of the list itself
		IPropertiesProviderListener* listener;		///< optional listener handling events

}; // class def




class IPropertiesProviderListener
 {
	public:
		/**
		 * @brief  Raised while a Property is being read.
		 * @param [in] property_curr the property object being read, may be updated by implementation
		 * @param [in] source the source (instance) of the event
		 * @return true to allow the processing; false will have PropertiesProvider returning an error
		 * @note   properties are locked, any other call within this scope will cause a DeadLock
		 */
		virtual bool readingProperty( Property* property_curr, const PropertiesProvider* source ) = 0;

		/**
		 * @brief  Raised while a Property is being updated.
		 * @param [out] property_new the (editable) property object which will replace old one. NULL means we are removing the old property
		 * @param [in] property_old the old (current) property being updated. NULL means we are adding a new property
		 * @param [in] source the source (instance) of the event
		 * @return true to allow the processing; false will have PropertiesProvider returning an error
		 * @note   properties are locked, any other call within this scope will cause a DeadLock
		 */
		virtual bool updatingProperty( bool& do_update, const Variant& value_proposed, Property& property_current, const PropertiesProvider* source ) = 0;

		virtual bool newProperty( Property* property_new, const PropertiesProvider* source ) {
			(void)property_new; (void)source;
			return true;
		 }

		virtual bool removingProperty( Property* property_old, const PropertiesProvider* source ) {
			(void)property_old; (void)source;
			return true;
		 }

	public:
		virtual ~IPropertiesProviderListener() { }

}; // class def


}; // namespace wosh

#endif //__WOSH_Core_PropertiesProvider_H__
